package gui;

import exceptions.ExReaderRssException;
import exceptions.ExXmlException;
import gui.graphicals.ToolBar;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.EtchedBorder;
import javax.xml.stream.XMLStreamException;
import readerRSS.*;

/**
 *
 * @author laetitia, thomas, tania Modifié le 11.05.2012 par Tania (liens avec
 * classes metier, technique et service)
 */
public class RSSReaderView extends AbstractModule implements ActionListener, MouseListener, KeyListener {

    private JList _myChannelList;
    private JScrollPane _myChannelListPanel;
    private JScrollPane _myItemListPanel;
    private JPanel _myItemContentPanel;
    private JList _myItemList;
    private JLabel _myTitleLabel;
    private JTextArea _myContentText;
    private JLabel _myStateBar;
    private ReaderRssController _myController;

    /**
     * Fenetre principale
     * @param mainWindow
     */
    public RSSReaderView(MainWindow mainWindow) {
        super(mainWindow);
    }

    @Override
    public void initController() {
        _myController = ReaderRssController.getInstance(this);
    }

    @Override
    protected ToolBar getToolBar() {
        ToolBar tb = new ToolBar();

        tb.makeButton("add_rss.png", "ADD", "S'abonner à un flux RSS", "ADD", this);
        tb.makeButton("delete_rss.png", "DELETE", "Se désabonner du flux sélectionné", "DELETE", this);
        tb.makeButton("refresh.png", "REFRESH ALL", " Tout mettre a jour", "REFRESH ALL", this);

        tb.addSeparator();

        tb.makeButton("next_unread.png", "NEXT UNREAD ELEMENT", "Aller au prochain element non lu", "NEXT UNREAD ELEMENT", this);
        tb.makeButton("read_element.png", "SET AS READ ELEMENT", "Marquer un element comme lu", "SET AS READ ELEMENT", this);

        tb.addSeparator();

        tb.makeButton("search.png", "SEARCH AN ELEMENT", "Rechercher un element", "SEARCH AN ELEMENT", this);

        return tb;
    }

    @Override
    protected JComponent getMainFrame() {

        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        // Initialise state bar
        _myStateBar = new JLabel("-");
        _myStateBar.setBorder(new EtchedBorder());
        panel.add(_myStateBar, BorderLayout.SOUTH);


        JSplitPane mainSP = new JSplitPane();

        // Panel with item list and item content
        JSplitPane subSP = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
                buildItemListPanel(),
                buildItemContentPanel());

        subSP.setDividerLocation(200);

        mainSP.setLeftComponent(buildChannelListPanel());
        mainSP.setRightComponent(subSP);
        mainSP.setDividerLocation(150);

        panel.add(mainSP, BorderLayout.CENTER);



        // Setup the contents of the frame
        return panel;
    }

    private JScrollPane buildChannelListPanel() {

        _myChannelList = new JList();
        _myChannelList.addMouseListener(new MouseListener() {

            @Override
            public void mouseClicked(MouseEvent me) {

                RssChannelModel selectedItem = (RssChannelModel) _myChannelList.getSelectedValue();

                if (selectedItem == null) {
                    return;
                }

                //readCurrentChosenFeed(selectedItem.getLink()); <= on a tout dans __controlChannels parce qu'on a chargé au début
                selectCurrentChosenFeed(selectedItem.getLink());
                //On recherche donc le flux là dedans
                _myStateBar.setText("Sélection du flux " + selectedItem.getLink());
                //System.out.println("Changement de flux dans l'arbre : " + selectedItem.getLink());
            }

            @Override
            public void mousePressed(MouseEvent me) {
            }

            @Override
            public void mouseReleased(MouseEvent me) {
            }

            @Override
            public void mouseEntered(MouseEvent me) {
            }

            @Override
            public void mouseExited(MouseEvent me) {
            }
        });

        updateAllChannelList(true);
        _myChannelListPanel = new JScrollPane(_myChannelList);

        return _myChannelListPanel;
    }

    /**
     * Change array to update channel list
     *
     * @param myListContent ArrayList of RssChannelModel
     */
    private void setChannelList(ArrayList<RssChannelModel> myListContent) {
        _myChannelList.setModel(new RssChannelListModel(myListContent));
    }

    /**
     * Update channel who is targetted by link
     *
     * @param link Link who need to be update
     */
    private void updateChannel(String link, boolean add) {

        _myStateBar.setText("Mise à jour du flux " + link + "...");

        try {
            _myController.setCurrentURL(link);

            if (add) {
                _myController.addChannelController(link);
            }

            _myController.readFeed(); //au chargement les controleurs sont OK

        } catch (XMLStreamException ex) {
            showDevErrorBox(ex);

        } catch (ExXmlException ex) {
            showDevErrorBox(ex);

        } catch (MalformedURLException ex) {
            showMalformedURLException(link);
        }


    }

    /**
     * Update list channel without add new channel controller
     *
     * @see updateAllChannelList(final boolean addLink)
     */
    private void updateAllChannelList() {
        updateAllChannelList(false);
    }

    /**
     * Call the method readFeedAb() to have all links and update every one
     *
     * @param addLink Add link to the controller channel list (default = false)
     */
    private void updateAllChannelList(final boolean addLink) {

        // ArrayList who contains all links in Rss list file
        final ArrayList<String> links;

        try {
            links = _myController.readFeedAb();

            // Thread to update all channel
            Thread t = new Thread() {

                @Override
                public void run() {

                    // For all channels links, we update it
                    for (String link : links) {
                        //updateChannel(link, addLink);  
                        updateChannel(link, addLink); //comme au démarrage du module... 
                        setChannelList(_myController.getChannelModels());
                    }

                    _myStateBar.setText("Tous les flux ont été chargés.");
                }
            };
            t.start();

        } catch (ExReaderRssException ex) {
            System.out.println("Le fichier d'abonnement n'a pas pu être lu - Erreur de démarrage");
            this.showDevErrorBox(ex);
        }
    }

    /**
     * Get the tree with list of all channels
     *
     * @return JTree
     *
     * private JTree buildChannelListTree() {
     *
     * DefaultMutableTreeNode root = new DefaultMutableTreeNode();
     * DefaultTreeModel model = new DefaultTreeModel(root);
     *
     * // Récupération d'une instance de _myControler if (_myController ==
     * null) { _myController = ReaderRssController.getInstance(this); }
     *
     * try { for (String elt : _myController.readFeedAb()) {
     * DefaultMutableTreeNode reader = new DefaultMutableTreeNode(elt);
     * root.add(reader); }
     *
     * // When configuration file is not found } catch (ExReaderRssException
     * ex) {
     *
     * showErrorBox("Le fichier que vous avez configuré n'est pas correct.\n\n"
     * + "Voilà ce qui a été saisi :\n" +
     * ReaderRssController.getListFeedAdresse() + "\n\n" + "Pour les
     * développeurs, modifier \n" + " private static String __listFeedAddress\n"
     * + " dans la classe ReaderRssController.", ex.getMessage());
     *
     * }
     *
     * _myChannelListTree = new JTree(root); _myChannelListTree.setModel(model);
     *
     * _myChannelListTree.setRootVisible(false);
     *
     * _myChannelListTree.getModel().addTreeModelListener(new
     * TreeModelListener() {
     *
     * @Override public void treeNodesChanged(TreeModelEvent tme) {
     * System.err.println("Renommage d'un flux... Évenement non attrapé..."); }
     *
     * @Override public void treeNodesInserted(TreeModelEvent tme) {
     * System.out.println("Nouveau flux"); _myController.addFeedAb("test_abo");
     * //ajout d'un abonnement test_abo passé en paramètre }
     *
     * @Override public void treeNodesRemoved(TreeModelEvent tme) {
     *
     * System.out.println("Suppression d'un flux");
     *
     * try { _myController.deleteFeedAb("test_abo"); //suppression d'un
     * abonnement passé en paramètre } catch (ExReaderRssException ex) {
     * Logger.getLogger(RSSReaderView.class.getName()).log(Level.SEVERE, null,
     * ex); } }
     *
     * @Override public void treeStructureChanged(TreeModelEvent tme) {
     * System.err.println("La structure de l'arbre a changé... Évenement non
     * attrapé."); } });
     *
     * _myChannelListTree.addTreeSelectionListener(new TreeSelectionListener() {
     *
     * @Override public void valueChanged(TreeSelectionEvent tse) {
     *
     * DefaultMutableTreeNode node = (DefaultMutableTreeNode)
     * _myChannelListTree.getLastSelectedPathComponent();
     *
     * // If nothing is selected if (node == null) return;
     *
     * System.out.println("Changement de flux dans l'arbre : " +
     * node.toString()); readCurrentChosenFeed(node.toString()); } });
     *
     * return _myChannelListTree; }
     */
    /**
     * Get the panel with list of all item
     *
     * @return JPanel
     */
    private JScrollPane buildItemListPanel() {

        _myItemList = new JList();
        _myItemList.addMouseListener(this);
        _myItemList.addKeyListener(this);//pour le déplacement avec touches flechees parmi articles

        _myItemListPanel = new JScrollPane(_myItemList);

        return _myItemListPanel;
    }

    /**
     * Update item list with a new array of items
     *
     * @param myListContent A ArrayList<RssItemModele> to fill the list item
     */
    private void setItemList(ArrayList<RssItemModel> myListContent) {
        _myItemList.setModel(new RssItemListModel(myListContent));
    }

    /**
     * Build area where one item content is show
     *
     * @return JPanel
     */
    private JPanel buildItemContentPanel() {

        _myItemContentPanel = new JPanel();
        _myItemContentPanel.setLayout(new BoxLayout(_myItemContentPanel, BoxLayout.PAGE_AXIS));

        _myTitleLabel = new JLabel();
        _myTitleLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
        _myTitleLabel.addMouseListener(this);

        _myContentText = new JTextArea();
        _myContentText.setLineWrap(true);
        _myContentText.setWrapStyleWord(true);

        _myItemContentPanel.add(_myTitleLabel);

        JScrollPane sp = new JScrollPane(_myContentText,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        _myItemContentPanel.add(sp);

        return _myItemContentPanel;
    }

    /**
     * Update item content area with another one
     *
     * @param myItem A RssItemModel to fill the item content
     */
    private void setItemContent(RssItemModel myItem) {
        _myTitleLabel.setText(myItem.getTitle());
        _myContentText.setText(myItem.getDescription());
    }

    @Override
    public void actionPerformed(ActionEvent ae) {

        if (ae.getActionCommand().equalsIgnoreCase("ADD")) {

            // Text field to fill an rss address
            String link = JOptionPane.showInputDialog(null,
                    "Adresse du nouveau flux à suivre :",
                    "Ajouter un flux",
                    JOptionPane.QUESTION_MESSAGE);

            // Add this chan to other
            System.out.println(link);
            updateChannel(link, true);
            _myController.addFeedAb(link);

            setChannelList(_myController.getChannelModels());
        }

        if (ae.getActionCommand().equalsIgnoreCase("DELETE")) {
            RssChannelModel selectedItem = (RssChannelModel) _myChannelList.getSelectedValue();
            String link = selectedItem.getLink();

            if (selectedItem == null) {
                return;
            }

            // Deletion of selectionned chan
            _myController.removeChannelController(link);
            try {
                _myController.deleteFeedAb(link);
            } catch (ExReaderRssException ex) {
                this.showDevErrorBox(ex);
            }

            setChannelList(_myController.getChannelModels());
            //updateAllChannelList();

        }

        if (ae.getActionCommand().equalsIgnoreCase("REFRESH ALL")) {

            _myController.reinitController();
            updateAllChannelList(true);
        }

        if (ae.getActionCommand().equalsIgnoreCase("NEXT UNREAD ELEMENT")) {
        }

        if (ae.getActionCommand().equalsIgnoreCase("SET AS READ ELEMENT")) {
        }

        if (ae.getActionCommand().equalsIgnoreCase("SEARCH AN ELEMENT")) {
        }
    }

    @Override
    public void mouseClicked(MouseEvent me) {

        RssItemModel selectedItem = (RssItemModel) _myItemList.getSelectedValue();

        if (selectedItem == null) {
            return;
        }

        if (me.getSource() == _myItemList) {
            this.setItemContent(selectedItem);
            String oldText = selectedItem.getTitle();
            if (!(selectedItem.getViewState() == 1)) {
                //si l'article n'est pas deja marque comme lu
                selectedItem.setTitle("(lu) " + oldText);
                selectedItem.setViewState(1);//indique que le contenu de l'item a été vu
            }
        } else if (me.getSource() == _myTitleLabel) {

            getMainWindow().changeModule("BROWSER");

            NavigatorView nav = (NavigatorView) getMainWindow().getModule("BROWSER");
            nav.addTab(selectedItem.getLink());
        }
    }

    @Override
    public void mousePressed(MouseEvent me) {
    }

    @Override
    public void mouseReleased(MouseEvent me) {
    }

    @Override
    public void mouseEntered(MouseEvent me) {

        RssItemModel selectedItem = (RssItemModel) _myItemList.getSelectedValue();
        if (selectedItem == null) {
            return;
        }

        if (me.getSource() == _myTitleLabel) {
            _myStateBar.setText("Ouvrir la page " + selectedItem.getLink());
        }

    }

    @Override
    public void mouseExited(MouseEvent me) {
        RssChannelModel selectedItem = (RssChannelModel) _myChannelList.getSelectedValue();

        if (selectedItem == null) {
            return;
        }

        _myStateBar.setText("Sélection du flux " + selectedItem.getLink());
    }

    /**
     * This method create an ArrayList of RssItemModel to update
     *
     * @param url
     */
    public void readCurrentChosenFeed(String url) {

        try {

            _myController.setCurrentURL(url);
            _myController.readFeed();
            setItemList(_myController.getChannelController(url).getChannelItems());

        } catch (NullPointerException ex) {
            this.showDevErrorBox(ex);

        } catch (XMLStreamException ex) {
            this.showDevErrorBox(ex);

        } catch (ExXmlException ex) {
            this.showDevErrorBox(ex);

        } catch (MalformedURLException ex) {
            showMalformedURLException(url);
        }
    }

    /**
     * Get infos about current feed
     * @param url
     */
    public void selectCurrentChosenFeed(String url) {

        setItemList(_myController.getChannelController(url).getChannelItems());
    }

    @Override
    public void keyTyped(KeyEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    //Evenement appui sur touche (par exemple, touche flechee)
    @Override
    public void keyPressed(KeyEvent e) {
        RssItemModel selectedItem = (RssItemModel) _myItemList.getSelectedValue();
        if (e.getSource() == _myItemList) {
            this.setItemContent(selectedItem);
            String oldText = selectedItem.getTitle();
            if (!(selectedItem.getViewState() == 1)) {
                //si l'article n'est pas deja marque comme lu
                selectedItem.setTitle("(lu) " + oldText);
                selectedItem.setViewState(1);//indique que le contenu de l'item a été vu
            }
        }
    }

    //Touche relachee (par exemple, touche flechee)
    @Override
    public void keyReleased(KeyEvent e) {
        //Mise à jour de l'affichage du detail de l'article
        RssItemModel selectedItem = (RssItemModel) _myItemList.getSelectedValue();
        if (e.getSource() == _myItemList) {
            this.setItemContent(selectedItem);
        }
    }
}
